/*
Access to Garmin MapSource files.
- Based on information provided by Ian Cowley.
+ Based on information provided by Ian Cowley & Mark Bradley
Copyright (C) 2002 Robert Lipe, robertlipe@usa.net
static char origname[256];
static const waypoint *prevRouteWpt;
+/* Private queues of written out waypoints */
+static queue written_wpt_head;
+static queue written_route_wpt_head;
+static void *written_wpt_mkshort_handle;
+
+/* Private queue of read in waypoints assumed to be used only for routes */
+static queue read_route_wpt_head;
+static void *read_route_wpt_mkshort_handle;
+
+#define MPSDEFAULTWPTCLASS 0
+#define MPSHIDDENROUTEWPTCLASS 8
#define MYNAME "MAPSOURCE"
#define ISME 0
#define NOTME 1
+#define DEFAULTICONDESCR "Waypoint"
+#define DEFAULTICONVALUE 18
+
char *snlen;
char *mpsverout;
char *mpsmergeout = NULL;
/* no-op */
}
+void
+mps_wpt_q_init(queue *whichQueue)
+{
+ QUEUE_INIT(whichQueue);
+}
+
+void
+mps_wpt_q_deinit(queue *whichQueue)
+{
+ queue *elem, *tmp;
+
+ QUEUE_FOR_EACH(whichQueue, elem, tmp) {
+ waypoint *q = (waypoint *) dequeue(elem);
+ waypt_free(q);
+ }
+}
+
+/*
+ * Find a waypoint that we've already written out
+ *
+ */
+waypoint *
+mps_find_wpt_q_by_name(const queue *whichQueue, const char *name)
+{
+ queue *elem, *tmp;
+ waypoint *waypointp;
+
+ QUEUE_FOR_EACH(whichQueue, elem, tmp) {
+ waypointp = (waypoint *) elem;
+ if (0 == strcmp(waypointp->shortname, name)) {
+ return waypointp;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Add a waypoint that we've already written out to our list
+ *
+ */
+void
+mps_wpt_q_add(const queue *whichQueue, const waypoint *wpt)
+{
+ waypoint *written_wpt = waypt_dupe(wpt);
+ written_wpt->Q.next = written_wpt->Q.prev = NULL;
+ ENQUEUE_TAIL(whichQueue, &written_wpt->Q);
+}
+
const char *
mps_find_desc_from_icon_number(const int icon, garmin_formats_e garmin_format)
{
fatal(MYNAME ": unknown garmin format");
}
}
- return "Waypoint";
+ return DEFAULTICONDESCR;
}
int
mps_find_icon_number_from_desc(const char *desc, garmin_formats_e garmin_format)
{
icon_mapping_t *i;
- int def_icon = 18;
+ int def_icon = DEFAULTICONVALUE;
if (!desc)
return def_icon;
int mps_converted_icon_number(const int icon_num, const int mpsver, garmin_formats_e garmin_format)
{
- int def_icon = 18;
+ int def_icon = DEFAULTICONVALUE;
switch (garmin_format) {
case MAPSOURCE:
mps_rd_init(const char *fname)
{
mps_file_in = xfopen(fname, "rb", MYNAME);
+
+ read_route_wpt_mkshort_handle = mkshort_new_handle();
+ /* initialise the "private" queue of waypoints read for routes */
+ mps_wpt_q_init(&read_route_wpt_head);
}
static void
mps_rd_deinit(void)
{
fclose(mps_file_in);
+ if ( read_route_wpt_mkshort_handle ) {
+ mkshort_del_handle( read_route_wpt_mkshort_handle );
+ }
+ /* flush the "private" queue of waypoints read for routes */
+ mps_wpt_q_deinit(&read_route_wpt_head);
}
static void
}
mps_file_out = xfopen(fname, "wb", MYNAME);
+
+ written_wpt_mkshort_handle = mkshort_new_handle();
+ /* initialise the "private" queue of waypoints written */
+ mps_wpt_q_init(&written_wpt_head);
+ mps_wpt_q_init(&written_route_wpt_head);
}
static void
fclose(mps_file_temp);
remove(tempname);
}
+
+ if ( written_wpt_mkshort_handle ) {
+ mkshort_del_handle( written_wpt_mkshort_handle );
+ }
+ /* flush the "private" queue of waypoints written */
+ mps_wpt_q_deinit(&written_wpt_head);
+ mps_wpt_q_deinit(&written_route_wpt_head);
}
/*
hdr[5] = 'A';
hdr[6] = 0;
strcpy(hdr+7,"Oct 20 1999");
- strcpy(hdr+19,"12:50:03");
+ strcpy(hdr+19,"12:50:33");
if (mps_ver == 4) {
hdr[1] = 0x96; /* equates to V4.06 */
strcpy(hdr+7,"Oct 22 2001");
- strcpy(hdr+19,"15:45:05");
+ strcpy(hdr+19,"15:45:33");
}
if (mps_ver == 5) {
hdr[1] = 0xF4; /* equates to V5.0 */
strcpy(hdr+7,"Jul 3 2003");
- strcpy(hdr+19,"08:35:39");
+ strcpy(hdr+19,"08:35:33");
}
reclen = 27; /* pre measured! */
* MRCB
*/
static void
-mps_waypoint_r(FILE *mps_file, int mps_ver, waypoint **wpt)
+mps_waypoint_r(FILE *mps_file, int mps_ver, waypoint **wpt, unsigned int *mpsclass)
{
char tbuf[100];
char wptname[256];
int lat;
int lon;
int icon;
- unsigned int mpsclass;
waypoint *thisWaypoint;
double mps_altitude = unknown_alt;
mps_readstr(mps_file, wptname, sizeof(wptname));
+ fread(mpsclass, 4, 1, mps_file); /* class */
+ (*mpsclass) = le_read32(mpsclass);
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
+
+ fread(tbuf,17, 1, mps_file); /* subclass data (17) */
+
if ((mps_ver == 4) || (mps_ver == 5)) {
- fread(&mpsclass, 4, 1, mps_file); /* class */
- mpsclass = le_read32(&mpsclass);
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
+ fread(tbuf, 5, 1, mps_file); /* additional subclass data (1) & terminator? (4) */
}
- fread(tbuf, 22, 1, mps_file); /* subclass data (18) + unknown (4) */
-
fread(&lat, 4, 1, mps_file);
fread(&lon, 4, 1, mps_file);
lat = le_read32(&lat);
lon = le_read32(&lon);
- fread(tbuf, 1, 1, mps_file); /* altitude validity */
+ fread(tbuf, 1, 1, mps_file); /* altitude validity */
if (tbuf[0] == 1) {
fread(&mps_altitude,sizeof(mps_altitude),1,mps_file);
}
mps_readstr(mps_file, wptdesc, sizeof(wptdesc));
- fread(tbuf, 1, 1, mps_file); /* proximity validity */
+ fread(tbuf, 1, 1, mps_file); /* proximity validity */
if (tbuf[0] == 1) {
fread(&mps_proximity,sizeof(mps_proximity),1,mps_file);
}
fread(tbuf,sizeof(mps_proximity),1, mps_file);
}
- fread(tbuf, 4, 1, mps_file); /* display flag */
- fread(tbuf, 4, 1, mps_file); /* colour */
- fread(&icon, 4, 1, mps_file); /* display symbol */
+ fread(tbuf, 4, 1, mps_file); /* display flag */
+ fread(tbuf, 4, 1, mps_file); /* colour */
+ fread(&icon, 4, 1, mps_file); /* display symbol */
icon = le_read32(&icon);
mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* city */
mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* state */
mps_readstr(mps_file, tbuf, sizeof(tbuf)); /*facility */
- fread(tbuf, 1, 1, mps_file); /* unknown */
+ fread(tbuf, 1, 1, mps_file); /* unknown */
- fread(tbuf, 1, 1, mps_file); /* depth validity */
+ fread(tbuf, 1, 1, mps_file); /* depth validity */
if (tbuf[0] == 1) {
fread(&mps_depth,sizeof(mps_depth),1,mps_file);
}
}
if ((mps_ver == 4) || (mps_ver == 5)) {
- fread(tbuf, 7, 1, mps_file); /* unknown */
+ fread(tbuf, 7, 1, mps_file); /* unknown */
}
else {
- fread(tbuf, 2, 1, mps_file); /* unknown */
+ fread(tbuf, 2, 1, mps_file); /* unknown */
}
thisWaypoint->shortname = xstrdup(wptname);
/* might need to change this to handle version dependent icon handling */
thisWaypoint->icon_descr = mps_find_desc_from_icon_number(icon, MAPSOURCE);
- waypt_add(thisWaypoint);
- return;
+ /* The following Now done elsewhere since it can be useful to read in and
+ perhaps not add to the list */
+ /* waypt_add(thisWaypoint); */
+ return;
}
/*
* MRCB
*/
static void
-mps_waypoint_w(FILE *mps_file, int mps_ver, const waypoint *wpt)
+mps_waypoint_w(FILE *mps_file, int mps_ver, const waypoint *wpt, const int isRouteWpt)
{
unsigned char hdr[100];
int reclen;
if ((mps_ver == 4) || (mps_ver == 5)) {
/* v4.06 & V5.0*/
reclen += 85; /* "W" (1) + strlen(name) + NULL (1) + class(4) + country(sz) +
- unknown(22) + lat(4) + lon(4) + alt(9) + strlen(desc) + NULL (1) +
- prox(9) + display(4) + colour(4) + symbol(4) + city(sz) + state(sz) +
- facility(sz) + unknown2(1) + depth(9) + unknown3(7) */
+ subclass(18) + unknown(4) + lat(4) + lon(4) + alt(9) + strlen(desc)
+ + NULL (1) + prox(9) + display(4) + colour(4) + symbol(4) + city(sz) +
+ state(sz) + facility(sz) + unknown2(1) + depth(9) + unknown3(7) */
/* -1 as reclen is interpreted from zero meaning a reclength of one */
}
else {
/* v3.02 */
- reclen += 75; /* "W" (1) + strlen(name) + NULL (1) + unknown(22) + lat(4) +
- lon(4) + alt(9) + strlen(desc) + NULL (1) + prox(9) + display(4) +
+ reclen += 75; /* "W" (1) + strlen(name) + NULL (1) + + class(4) + country(sz) +
+ subclass(17) + lat(4) + lon(4) + alt(9) + strlen(desc) +
+ NULL (1) + prox(9) + display(4) +
colour(4) + symbol(4) + city(sz) + state(sz) + facility(sz) +
unknown2(1) + depth(9) + unknown3(2) */
/* -1 as reclen is interpreted from zero meaning a reclength of one */
fwrite(&reclen, 4, 1, mps_file);
fwrite("W", 1, 1, mps_file);
fputs(ident, mps_file);
- fwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
+ fwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
+
+ if (isRouteWpt) zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
+ else zbuf[0] = (char)MPSDEFAULTWPTCLASS;
+ fwrite(zbuf, 4, 1, mps_file); /* class */
+
+ zbuf[0]=0;
+ fwrite(zbuf, 1, 1, mps_file); /* country empty string */
if ((mps_ver == 4) || (mps_ver == 5)) {
- fwrite(zbuf, 4, 1, mps_file); /* class */
- fwrite(zbuf, 1, 1, mps_file); /* country */
- fwrite(zbuf, 4, 1, mps_file); /* unknown */
- fwrite(ffbuf, 12, 1, mps_file); /* unknown */
- fwrite(zbuf, 2, 1, mps_file); /* unknown */
+ fwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
+ fwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
+ fwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
fwrite(ffbuf, 4, 1, mps_file); /* unknown */
}
else {
- fwrite(zbuf, 13, 1, mps_file);
+ fwrite(zbuf, 8, 1, mps_file);
fwrite(ffbuf, 8, 1, mps_file);
fwrite(zbuf, 1, 1, mps_file);
}
}
}
+/*
+ * wrapper to include the mps_ver_out information
+ * A waypoint is only written if it hasn't been written before
+ * based on it shortname alone
+ *
+ */
+static void
+mps_waypoint_w_unique_wrapper(const waypoint *wpt)
+{
+ waypoint *wptfound = NULL;
+
+ /* Search for this waypoint in the ones already written */
+ wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname);
+ /* is the next line necessary? Assumes we know who's called us and in what order */
+ if (wptfound == NULL)
+ wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname);
+
+ /* if this waypoint hasn't been written then it is okay to do so */
+ if (wptfound == NULL) {
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0));
+
+ /* ensure we record in our "private" queue what has been
+ written so that we don't write it again */
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
+}
+
+/*
+ * wrapper to include the mps_ver_out information
+ * A waypoint is only written if it hasn't been written before
+ * based on it shortname alone
+ * Provided as a separate function from above in case we find
+ * have to do other things
+ *
+ */
static void
-mps_waypoint_w_wrapper(const waypoint *wpt)
+mps_route_wpt_w_unique_wrapper(const waypoint *wpt)
{
- mps_waypoint_w(mps_file_out, mps_ver_out, wpt);
+ waypoint *wptfound = NULL;
+
+ /* Search for this waypoint in the ones already written */
+ wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname);
+ if (wptfound == NULL)
+ /* so, not a real wpt, so must check route wpts already written as reals */
+ wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname);
+
+ /* if this waypoint hasn't been written then it is okay to do so
+ but assume it is only required for the route
+ */
+ if (wptfound == NULL) {
+ /* Although we haven't written one out, this might still be a "real" waypoint
+ If so, we need to write it out now accordingly */
+ wptfound = find_waypt_by_name (wpt->shortname);
+
+ if (wptfound == NULL) {
+ /* well, we tried to find: it wasn't written and isn't a real waypoint */
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==1));
+ mps_wpt_q_add(&written_route_wpt_head, wpt);
+ }
+ else {
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0));
+ /* Simulated real user waypoint */
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
+ }
+}
+
+/*
+ * wrapper to include the mps_ver_out information
+ * This one always writes a waypoint. If it has been written before
+ * then generate a unique name before writing
+ *
+ */
+static void
+mps_waypoint_w_uniqloc_wrapper(waypoint *wpt)
+{
+ waypoint *wptfound = NULL;
+ char *newName;
+ unsigned int uniqueNum = 0;
+
+ /* Search for this waypoint in the ones already written */
+ wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname);
+ /* is the next line necessary? Assumes we know who's called us and in what order */
+ if (wptfound == NULL)
+ wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname);
+
+ if (wptfound != NULL) {
+ /* check if this is the same waypoint by looking at the lat lon
+ not ideal, but better then having two same named waypoints
+ that kills MapSource. If it is the same then don't bother
+ adding it in. If it isn't, then rename it
+ */
+ if (((wpt->latitude - wptfound->latitude) != 0) ||
+ ((wpt->longitude - wptfound->longitude) != 0)) {
+ /* Not the same lat lon, so rename and add */
+ newName = mkshort(written_wpt_mkshort_handle, wpt->shortname);
+ wptfound = waypt_dupe(wpt);
+ wptfound->Q.next = wptfound->Q.prev = NULL;
+ xfree(wptfound->shortname);
+ wptfound->shortname = newName;
+ mps_waypoint_w(mps_file_out, mps_ver_out, wptfound, (1==0));
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
+ }
+ else {
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, (1==0));
+ /* ensure we record in out "private" queue what has been
+ written so that we don't write it again */
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
}
/*
int interlinkStepCount;
int thisInterlinkStep;
unsigned int mpsclass;
+ int FFsRead;
time_t dateTime = 0;
route_head *rte_head;
while (rte_count--) {
mps_readstr(mps_file, wptname, sizeof(wptname));
+ fread(&mpsclass, 4, 1, mps_file); /* class */
+ mpsclass = le_read32(&mpsclass);
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
+
if ((mps_ver == 4) || (mps_ver == 5)) {
- fread(&mpsclass, 4, 1, mps_file); /* class */
- mpsclass = le_read32(&mpsclass);
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
fread(tbuf, 18, 1, mps_file); /* subclass data */
- if (mpsclass != 0) {
- fread(tbuf, 8, 1, mps_file); /* unknown 8 x 0xFF */
- }
- fread(tbuf, 4, 1, mps_file); /* unknown 4 x 0xFF */
- fread(tbuf, 19, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
+ /* This is a bit unpleasant. Routes have a variable length of
+ data that is terminated by the five bytes:
+ 0xFF 0xFF 0xFF 0xFF <not 0xFF>
+ So, need to skip over the variable portion and stop after
+ we found the terminator
+ */
+ FFsRead = tbuf[1] = 0;
+ do {
+ fread(tbuf, 1, 1, mps_file);
+ if (tbuf[0] == -1) {
+ if ((FFsRead == 0) || (tbuf[1] == -1)) FFsRead++;
+ }
+ else if (FFsRead < 4) FFsRead = 0;
+ tbuf[1]=tbuf[0];
+ } while ((FFsRead < 4) || (tbuf[0] == -1));
+
+ /* The next thing is the unknown 0x00 0x03 0x00 .. 0x00 (19 bytes)
+ but in looking for Arnie above we have read the first of these
+ so, only read 18 bytes
+ */
+ fread(tbuf, 18, 1, mps_file);
}
else {
- fread(tbuf, 22, 1, mps_file); /* unknown */
- fread(tbuf, 18, 1, mps_file); /* unknown */
+ fread(tbuf, 17, 1, mps_file); /* subclass data */
+ fread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
}
/* link details */
}
/* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
- if found */
+ if found. With MapSource, one should consider the real waypoint list as definitive */
tempWpt = find_waypt_by_name(wptname);
if (tempWpt != NULL) {
thisWaypoint = waypt_dupe(tempWpt);
+ thisWaypoint->Q.next = thisWaypoint->Q.prev = NULL;
}
else {
- thisWaypoint = xcalloc(sizeof(*thisWaypoint), 1);
- thisWaypoint->shortname = xstrdup(wptname);
- thisWaypoint->latitude = lat / 2147483648.0 * 180.0;
- thisWaypoint->longitude = lon / 2147483648.0 * 180.0;
- thisWaypoint->altitude = mps_altitude;
- thisWaypoint->depth = mps_depth;
+ tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname);
+
+ if (tempWpt != NULL) {
+ thisWaypoint = waypt_dupe(tempWpt);
+ thisWaypoint->Q.next = thisWaypoint->Q.prev = NULL;
+ }
+ else {
+ /* should never reach here, but we do need a fallback position */
+ thisWaypoint = waypt_new();
+ thisWaypoint->shortname = xstrdup(wptname);
+ thisWaypoint->latitude = lat / 2147483648.0 * 180.0;
+ thisWaypoint->longitude = lon / 2147483648.0 * 180.0;
+ thisWaypoint->altitude = mps_altitude;
+ thisWaypoint->depth = mps_depth;
+ }
}
route_add_wpt(rte_head, thisWaypoint);
/* all we want is the waypoint name; lat, lon and alt are already set from above */
mps_readstr(mps_file, wptname, sizeof(wptname));
- if ((mps_ver == 4) || (mps_ver == 5)) {
+ fread(&mpsclass, 4, 1, mps_file); /* class */
+ mpsclass = le_read32(&mpsclass);
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
- fread(&mpsclass, 4, 1, mps_file); /* class */
- mpsclass = le_read32(&mpsclass);
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
+ if ((mps_ver == 4) || (mps_ver == 5)) {
fread(tbuf, 18, 1, mps_file); /* subclass data */
- fread(tbuf, 4, 1, mps_file); /* unknown 4 x 0xFFs */
- fread(tbuf, 19, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
+ /* This is a bit unpleasant. Routes have a variable length of
+ data that is terminated by the five bytes:
+ 0xFF 0xFF 0xFF 0xFF <not 0xFF>
+ So, need to skip over the variable portion and stop after
+ we found the terminator
+ */
+ FFsRead = tbuf[1] = 0;
+ do {
+ fread(tbuf, 1, 1, mps_file);
+ if (tbuf[0] == -1) {
+ if ((FFsRead == 0) || (tbuf[1] == -1)) FFsRead++;
+ }
+ else if (FFsRead < 4) FFsRead = 0;
+ tbuf[1]=tbuf[0];
+ } while ((FFsRead < 4) || (tbuf[0] == -1));
+
+ /* The next thing is the unknown 0x00 0x03 0x00 .. 0x00 (19 bytes)
+ but in looking for Arnie above we have read the first of these
+ so, only read 18 bytes
+ */
+ fread(tbuf, 18, 1, mps_file);
}
else {
- fread(tbuf, 22, 1, mps_file); /* unknown */
- fread(tbuf, 18, 1, mps_file); /* unknown */
+ fread(tbuf, 17, 1, mps_file); /* subclass data */
+ fread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
}
fread(tbuf, 5, 1, mps_file); /* 5 byte trailer */
/* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
- if found */
+ if found because there is more info held in a real waypoint than in its route counterpart,
+ e.g. the display symbol (aka icon)
+ */
tempWpt = find_waypt_by_name(wptname);
if (tempWpt != NULL) {
thisWaypoint = waypt_dupe(tempWpt);
+ thisWaypoint->Q.next = thisWaypoint->Q.prev = NULL;
}
else {
- thisWaypoint = xcalloc(sizeof(*thisWaypoint), 1);
+ thisWaypoint = waypt_new();
thisWaypoint->shortname = xstrdup(wptname);
thisWaypoint->latitude = lat / 2147483648.0 * 180.0;
thisWaypoint->longitude = lon / 2147483648.0 * 180.0;
route lat lon min (2x4) + route min alt (9) +
num route datapoints value (4) */
- /* V3 - each waypoint: waypoint name + NULL (1) + unknown (22) + unknown (18) */
+ /* V3 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
+ subclass (17) + unknown (18) */
/* V4,5 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
- unknown (22) + unknown (19) */
+ subclass (18) + unknown (4) + unknown (19) */
/* V* - each route link: 0x00000002 (4) + end 1 lat (4) + end 1 lon (4) + end 1 alt (9) +
end 2 lat (4) + end 2 lon (4) + end 2 alt (9) + NULL (1) +
link max lat (4) + link max lon (4) + link max alt (9) +
mps_routedatapoint_w(FILE *mps_file, int mps_ver, const waypoint *rtewpt)
{
unsigned char hdr[10];
- int lat;
- int lon;
- time_t t = rtewpt->creation_time;
- char zbuf[20];
- char ffbuf[20];
- char *src;
- char *ident;
+ int lat;
+ int lon;
+ time_t t = rtewpt->creation_time;
+ char zbuf[20];
+ char ffbuf[20];
+ char *src;
+ char *ident;
int reclen;
int maxlat;
double maxalt=unknown_alt;
double minalt=unknown_alt;
- double mps_altitude;
+ double mps_altitude;
+ waypoint *wptfound;
memset(zbuf, 0, sizeof(zbuf));
memset(ffbuf, 0xff, sizeof(ffbuf));
fputs(ident, mps_file);
fwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
- if ((mps_ver == 4) || (mps_ver == 5)) {
- /* unknown */
- fwrite(zbuf, 4, 1, mps_file); /* class */
- fwrite(zbuf, 1, 1, mps_file); /* country - i.e. empty string */
+ wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, ident);
+ if (wptfound != NULL) zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
+ else zbuf[0] = (char)MPSDEFAULTWPTCLASS;
+ fwrite(zbuf, 4, 1, mps_file); /* class */
+
+ zbuf[0]=0;
+ fwrite(zbuf, 1, 1, mps_file); /* country - i.e. empty string */
- /* unknown, exactly as for waypoints */
- fwrite(zbuf, 4, 1, mps_file);
- fwrite(ffbuf, 12, 1, mps_file);
- fwrite(zbuf, 2, 1, mps_file);
- fwrite(ffbuf, 4, 1, mps_file);
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ fwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
+ fwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
+ fwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
+ fwrite(ffbuf, 4, 1, mps_file); /* unknown */
fwrite(zbuf, 1, 1, mps_file);
hdr[0] = 3;
fwrite(zbuf, 17, 1, mps_file);
}
else {
- /* unknown, exactly as for waypoints */
- fwrite(zbuf, 13, 1, mps_file);
- fwrite(ffbuf, 8, 1, mps_file);
- fwrite(zbuf, 1, 1, mps_file);
-
+ fwrite(zbuf, 8, 1, mps_file); /* subclass part 1 */
+ fwrite(ffbuf, 8, 1, mps_file); /* subclass part 2 */
+ fwrite(zbuf, 1, 1, mps_file); /* subclass part 3 */
/* unknown */
fwrite(zbuf, 1, 1, mps_file);
}
prevRouteWpt = rtewpt;
-
}
static void
/*
- * read in from file a route record
+ * read in from file a track record
* MRCB
*/
static void
fread(tbuf,sizeof(mps_depth),1, mps_file);
}
- thisWaypoint = xcalloc(sizeof(*thisWaypoint), 1);
+ thisWaypoint = waypt_new();
thisWaypoint->latitude = lat / 2147483648.0 * 180.0;
thisWaypoint->longitude = lon / 2147483648.0 * 180.0;
thisWaypoint->creation_time = le_read32(&dateTime);
static void
mps_read(void)
{
- waypoint *wpt;
- route_head *rte;
- route_head *trk;
+ waypoint *wpt;
+ route_head *rte;
+ route_head *trk;
- char recType;
- int reclen;
- int morework;
+ char recType;
+ int reclen;
+ int morework;
+ unsigned int mpsWptClass;
mps_ver_in = 0; /* although initialised at declaration, what happens if there are two mapsource
input files? */
case 'W':
/* Waypoint record */
/* With routes, we need the waypoint info that reveals, for example, the symbol type */
- mps_waypoint_r(mps_file_in, mps_ver_in, &wpt);
+ mps_waypoint_r(mps_file_in, mps_ver_in, &wpt, &mpsWptClass);
+ /* only add to the "real" list if a "user" waypoint otherwise add to the private list */
+ if (mpsWptClass == MPSDEFAULTWPTCLASS) waypt_add(wpt);
+ else mps_wpt_q_add(&read_route_wpt_head, wpt);
#ifdef DUMP_ICON_TABLE
printf("\t{ %4u, \"%s\" },\n", icon, wpt->shortname);
#endif
void
mps_write(void)
{
- int short_length;
- waypoint *wpt;
- route_head *rte;
- route_head *trk;
-
- char recType;
- int reclen;
- int reclen2;
- unsigned int tocopy;
+ int short_length;
+ waypoint *wpt;
+ route_head *rte;
+ route_head *trk;
+
+ char recType;
+ int reclen;
+ int reclen2;
+ unsigned int tocopy;
+ long tempFilePos;
+ unsigned int mpsWptClass;
unsigned char copybuf[8192];
if (mpsverout) {
if (mps_ver_temp != atoi(mpsverout)) {
+ /* Need to clean up after a junk version specified */
+ /* close the real output file + renamed original output file */
+ /* then delete the "real" file and rename the temporarily renamed file back */
fclose(mps_file_temp);
fclose(mps_file_out);
remove(origname);
mps_fileHeader_w(mps_file_out, mps_ver_out);
+ /* .mps file order is wpts, rtes, trks then mapsets. If we've not been asked to write
+ wpts, but we are merging, then read in the waypoints from the original file and
+ write them out, prior to doing rtes.
+ */
if ((mpsmergeout) && (global_opts.objective != wptdata)) {
while (!feof(mps_file_temp)) {
fwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
fwrite(&recType, 1, 1, mps_file_out);
+ tempFilePos = ftell(mps_file_temp);
+ /* need to read in the waypoint info only because later we may need to check for uniqueness
+ since we're here because the user didn't request waypoints, this should be acceptable */
+ mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ /* now return to the start of the waypoint data to do a "clean" copy */
+ fseek(mps_file_temp, tempFilePos, SEEK_SET);
+
+ /* copy the data using a "reasonably" sized buffer */
for(tocopy = reclen2; tocopy > 0; tocopy -= sizeof(copybuf)) {
fread(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_temp);
fwrite(copybuf, (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy), 1, mps_file_out);
} /* while (!feof(mps_file_temp)) */
} /* if (mpsmergeout) */
+ /* irrespective of merging, now write out any waypoints */
if (global_opts.objective == wptdata) {
if (mpsmergeout) {
fread(&recType, 1, 1, mps_file_temp);
if (recType == 'W') {
- mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt);
+ /* need to be careful that we aren't duplicating a wpt defined from elsewhere */
+ mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
+ if (mpsWptClass == MPSDEFAULTWPTCLASS) waypt_add(wpt);
}
else break;
}
}
- waypt_disp_all(mps_waypoint_w_wrapper);
+ waypt_disp_all(mps_waypoint_w_unique_wrapper);
}
+ /* prior to writing any tracks as requested, if we're doing a merge, read in the rtes
+ from the original file and then write them out, ready for tracks to follow
+ */
if ((mpsmergeout) && (global_opts.objective != rtedata)) {
while (!feof(mps_file_temp)) {
+ /* this might all fail if the relevant waypoints haven't been written */
if (recType == 'R') {
fwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
fwrite(&recType, 1, 1, mps_file_out);
} /* while (!feof(mps_file_temp)) */
} /* if (mpsmergeout) */
+ /* routes are next in the wpts, rtes, trks, mapset sequence */
if (global_opts.objective == rtedata) {
if (mpsmergeout) {
fread(&recType, 1, 1, mps_file_temp);
}
}
- /* need to make sure there is a "real" waypoint for each route waypoint */
- route_disp_all(mps_noop, mps_noop, mps_waypoint_w_wrapper);
+ /* need to make sure there is a "real" waypoint for each route waypoint
+ Need to be careful about creating duplicate wpts as MapSource chokes on these
+ so, if the user requested waypoints to be output too, then write the route
+ waypoints only if unique in the total list of waypoints ("real" and route derived)
+ If the user didn't request waypoints to be output, then output the route derived
+ waypoints without consideration for uniqueness for "real" waypoints that haven't
+ been output (phew!)
+ */
+ route_disp_all(mps_noop, mps_noop, mps_route_wpt_w_unique_wrapper);
+
route_disp_all(mps_routehdr_w_wrapper, mps_routetrlr_w_wrapper, mps_routedatapoint_w_wrapper);
}
+ /* If merging but we haven't been requested to write out tracks, then read in tracks from
+ the original file and write these out prior to any mapset writes later on
+ */
if ((mpsmergeout) && (global_opts.objective != trkdata)) {
while (!feof(mps_file_temp)) {
} /* while (!feof(mps_file_temp)) */
} /* if (mpsmergeout) */
+ /* tracks are next in the wpts, rte, trks, mapset sequence in .mps files */
if (global_opts.objective == trkdata) {
if (mpsmergeout) {
/* since we're processing tracks, we should read in from whatever version and write out
#define LINELENGTH 200
#define MYNAME "MkWinTesto"
-// ------------------------------------------------------------------------------------
+/* ------------------------------------------------------------------------------------ */
int f_outputLine (
char *pcWhat,
FILE *pfWhere)
int iLength;
int iThisChar;
- // ===========================
- // Returns 0 is output has new line
- // Returns 1 is line ended on \ for continuation and no new line
+ /* ===========================
+ Return 0 = output has new line
+ Return 1 = line ended on \ for continuation and no new line
+ */
iLength = strlen(pcWhat);
if (iLength > 2) {
return 0;
}
-// ------------------------------------------------------------------------------------
+/* ------------------------------------------------------------------------------------ */
int main(
int argc,
char *argv[])
int iTranslateQuotes;
int iQuoteCount;
int iPrevLineContinues = 0;
+ int iEchoLevel = 0;
FILE *pfTestoIn;
FILE *pfTestoOut;
- // ===========================
+ /* =========================== */
if (argc < 2) {
fatal(MYNAME ": needs a single parameter, the (testo) file to convert\n");
}
else {
- // Output the .CMD preamble
+ /* Output the .CMD preamble */
f_outputLine("@echo off", pfTestoOut);
f_outputLine("REM", pfTestoOut);
f_outputLine("REM Simple Windows NT/2000/XP .cmd version of GPSBabel testo script", pfTestoOut);
f_outputLine("REM Test if param2 was a dir rather than a file, if so add a \\* to make fc work", pfTestoOut);
f_outputLine("FOR %%A IN (%2) DO IF \"d--------\"==\"%%~aA\" SET PARAM2=%2\\*", pfTestoOut);
f_outputLine("FOR /f \"delims=\" %%a IN ('fc %PARAM1% %PARAM2%') DO IF \"x%%a\"==\"xFC: no differences encountered\" GOTO :EOF", pfTestoOut);
- f_outputLine("ECHO %* are not the same - pausing. ^C to quit if required", pfTestoOut);
+ f_outputLine("REM Show the first 5 lines of difference", pfTestoOut);
+ f_outputLine("fc /LB5 %PARAM1% %PARAM2%", pfTestoOut);
+ f_outputLine("ECHO %* are not the same (first 5 differences above) - pausing. ^C to quit if required", pfTestoOut);
f_outputLine("PAUSE", pfTestoOut);
f_outputLine("GOTO :EOF", pfTestoOut);
f_outputLine("", pfTestoOut);
while (! feof(pfTestoIn)) {
- // Read in the next line or stop if done
+ /* Read in the next line or stop if done */
fgets(acLineIn, LINELENGTH-1, pfTestoIn);
if (acLineIn == NULL) break;
- // Is the whole line a comment? Replace the hash with REM and output the rest
+ /* Is the whole line a comment? Replace the hash with REM and output the rest */
if (acLineIn[0] == '#') {
acLineOut[0]='\0';
strcat (acLineOut,"REM");
- // Strip out any ending new lines
+ /* Strip out any ending new lines */
for (iThisChar=1; iThisChar<LINELENGTH; iThisChar++) {
if ((acLineIn[iThisChar] == '\0') ||
(acLineIn[iThisChar] == '\n') ||
}
acLineOut[iThisChar+2] = acLineIn[iThisChar];
}
+ if (iEchoLevel > 0) {
+ f_outputLine("@echo off", pfTestoOut);
+ f_outputLine("@echo.", pfTestoOut);
+ iEchoLevel = 0;
+ }
iPrevLineContinues = f_outputLine(acLineOut, pfTestoOut);
}
- // Are we near the top of testo where the program variable is defined?
+ /* Are we near the top of testo where the program variable is defined? */
else if (strncmp("PNAME=${PNAME:-",acLineIn,15) == 0) {
acLineOut[0]='\0';
strcat (acLineOut,"SET PNAME=");
- // Copy the rest of the PNAME assignment stopping at a close } or EOL
+ /* Copy the rest of the PNAME assignment stopping at a close } or EOL */
for (iThisChar=15; iThisChar<LINELENGTH; iThisChar++) {
if ((acLineIn[iThisChar] == '}') ||
(acLineIn[iThisChar] == '\0') ||
acLineOut[iThisChar-5] = acLineIn[iThisChar];
}
}
+ if (iEchoLevel > 0) {
+ f_outputLine("@echo off", pfTestoOut);
+ f_outputLine("@echo.", pfTestoOut);
+ iEchoLevel = 0;
+ }
iPrevLineContinues = f_outputLine(acLineOut, pfTestoOut);
if (iPrevLineContinues == 1) f_outputLine("", pfTestoOut);
iPrevLineContinues = f_outputLine("IF NOT EXIST %PNAME% ECHO Can't find %PNAME%&& GOTO :EOF", pfTestoOut);
- // fputs("\r\n", pfTestoOut);
+ /* fputs("\r\n", pfTestoOut); */
}
else {
- // Every other line....
+ /* Every other line.... */
iStart = 0;
iTarget = 0;
iTranslateQuotes = 0;
iQuoteCount = 0;
acLineOut[0] = '\0';
- // Is this one of the test sequences mostly (all?) starting with a cleanup?
+ /* Is this one of the test sequences mostly (all?) starting with a cleanup? */
if (strncmp("rm -f ",acLineIn,6) == 0) {
+ if (iEchoLevel > 0) {
+ f_outputLine("@echo off", pfTestoOut);
+ f_outputLine("@echo.", pfTestoOut);
+ iEchoLevel = 0;
+ }
iStart = 6;
strcat(acLineOut, "DEL ");
iTarget = 4;
}
- // Is this one of the test sequences where the program is run?
+ /* Is this one of the test sequences where the program is run? */
if (strncmp("${PNAME} ",acLineIn,9) == 0) {
iStart = 9;
+ iEchoLevel++;
strcat(acLineOut, "%PNAME% ");
iTarget = 8;
}
- // Is this one of the test sequences where we compare the rest?
+ /* Is this one of the test sequences where we compare the rest? */
if (strncmp("compare ",acLineIn,8) == 0) {
+ if (iEchoLevel > 0) {
+ f_outputLine("@echo off", pfTestoOut);
+ f_outputLine("@echo.", pfTestoOut);
+ iEchoLevel = 0;
+ }
iStart = 8;
strcat(acLineOut, "CALL :COMPARE ");
iTarget = 14;
}
- // Is this one of the test sequences where we compare the rest?
+ /* Is this one of the test sequences where we compare the rest? */
if (strncmp("sort_and_compare ",acLineIn,17) == 0) {
+ if (iEchoLevel > 0) {
+ f_outputLine("@echo off", pfTestoOut);
+ f_outputLine("@echo.", pfTestoOut);
+ iEchoLevel = 0;
+ }
iStart = 17;
strcat(acLineOut, "CALL :SORTandCOMPARE ");
iTarget = 21;
}
- // Is this one of the test sequences where we prepare some data?
+ /* Is this one of the test sequences where we prepare some data? */
if (strncmp("echo \"",acLineIn,6) == 0) {
+ if (iEchoLevel > 0) {
+ f_outputLine("@echo off", pfTestoOut);
+ f_outputLine("@echo.", pfTestoOut);
+ iEchoLevel = 0;
+ }
iStart = 6;
strcat(acLineOut, "ECHO ");
iTarget = 5;
(iPrevLineContinues == 1)) {
if (iStart == 0) {
- // Didn't match, so can only possibly be a continued line
- // Skip spaces, then process the rest of line as "normal"
+ /* Didn't match, so can only possibly be a continued line
+ Skip spaces, then process the rest of line as "normal" */
for (iThisChar=0; iThisChar<LINELENGTH; iThisChar++) {
- // end of line checks
+ /* end of line checks */
if ((acLineIn[iThisChar] == '\0') ||
(acLineIn[iThisChar] == '\n') ||
((acLineIn[iThisChar] == '\r') && (acLineIn[iThisChar+1] == '\n'))) {
iStart = iThisChar;
break;
}
- // Stop skipping spaces and tabs if this isn't one (arg!)
+ /* Stop skipping spaces and tabs if this isn't one (arg!) */
if ((acLineIn[iThisChar] != ' ') &&
(acLineIn[iThisChar] != '\t')) {
iStart = iThisChar;
break;
}
- } // for ... skipping spaces on a continued line
- } // if... is this a continued line?
+ } /* for ... skipping spaces on a continued line */
+ } /* if... is this a continued line? */
- // Need to replace the shell variable replacement syntax with Windoze one
- // and swap slashes in directory separators
+ /* Need to replace the shell variable replacement syntax with Windoze one
+ and swap slashes in directory separators
+ */
for (iThisChar=iStart; iThisChar<LINELENGTH; iThisChar++) {
if ((acLineIn[iThisChar] == '\0') ||
break;
}
if (acLineIn[iThisChar] == '"') {
- // Are we starting quotes or in quotes?
- // Either way, don't copy out the quotes themselves
+ /* Are we starting quotes or in quotes?
+ Either way, don't copy out the quotes themselves */
iQuoteCount = (iQuoteCount > 0) ? 0 : 1;
iTarget--;
continue;
}
if (acLineIn[iThisChar] == '%') {
if (iQuoteCount == 1) {
- // Need to double up the number of %s
+ /* Need to double up the number of %s */
acLineOut[iTarget+iThisChar-iStart] = '%';
iTarget++;
}
- // This also caters for where we're not in quotes,
- // so must just copy the % once
+ /* This also caters for where we're not in quotes,
+ so must just copy the % once */
acLineOut[iTarget+iThisChar-iStart] = '%';
continue;
}
if (acLineIn[iThisChar] == '>') {
if (acLineIn[iThisChar-1] == ' ') {
- // Need to remove any spaces between echo and redirection
- // as NT/2000/XP adds this to the output and mostly this is NOT wanted
+ /* Need to remove any spaces between echo and redirection
+ as NT/2000/XP adds this to the output and mostly this is NOT wanted */
iTarget--;
}
acLineOut[iTarget+iThisChar-iStart] = '>';
}
if (strncmp("${TMPDIR}",acLineIn+iThisChar,9) == 0) {
strcpy(acLineOut+iTarget+iThisChar-iStart,"%TMPDIR%");
- // %TMPDIR% is one char shorter than ${TMPDIR}
+ /* %TMPDIR% is one char shorter than ${TMPDIR} */
iTarget--;
- // skip forward to the end of the string matched
- // (less one as the loop will add one)
+ /* skip forward to the end of the string matched
+ (less one as the loop will add one) */
iThisChar += 8;
} else if (acLineIn[iThisChar] == '/') {
acLineOut[iTarget+iThisChar-iStart] = '\\';
} else {
- // part of a literal, so copy the text
+ /* part of a literal, so copy the text */
acLineOut[iTarget+iThisChar-iStart] = acLineIn[iThisChar];
}
- } // for
+ } /* for */
+ if ((iEchoLevel == 1) && (iPrevLineContinues != 1)) {
+ f_outputLine("@echo on", pfTestoOut);
+ f_outputLine("@echo Testing...", pfTestoOut);
+ }
iPrevLineContinues = f_outputLine(acLineOut, pfTestoOut);
- // fputs("\r\n", pfTestoOut);
+ /* fputs("\r\n", pfTestoOut); */
}
else {
- // We didn't match the start of the line, so
- // - if blank, print it
-
+ /* We didn't match the start of the line, so
+ - if blank, print it
+ */
+ if (iEchoLevel > 0) {
+ f_outputLine("@echo off", pfTestoOut);
+ f_outputLine("@echo.", pfTestoOut);
+ iEchoLevel = 0;
+ }
if ((acLineIn[0] == '\n') ||
(acLineIn[0] == '\0') ||
((acLineIn[0] == '\r') && (acLineIn[1] == '\n') && (acLineIn[2] == '\0'))) {
iPrevLineContinues = f_outputLine("", pfTestoOut);
}
- } // else... didn't match a start of line - so check rest of line
+ } /* else... didn't match a start of line - so check rest of line */
- } // else ... catchall to mathing things on the start of the line
+ } /* else ... catchall to mathing things on the start of the line */
- } // while <stuff to read>
+ } /* while <stuff to read> */
- // We're done
+ /* We're done */
fclose(pfTestoIn);
fclose(pfTestoOut);
}